package com.example.questionsystem.modules.qu.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;

import cn.hutool.log.StaticLog;
import com.example.questionsystem.modules.qu.util.AESDecryptor;
import com.google.common.hash.Hashing;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;


import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.concurrent.TimeUnit;

public class ImageDownloader {
    private static final CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionTimeToLive(30, TimeUnit.SECONDS)
            .setMaxConnTotal(50)
            .build();
    private static final int DOWNLOAD_TIMEOUT = 30000; // 30秒超时 ;
    /**
     * 下载远程图片，先进行base64编码，再使用AES PCK7填充模式加密，最后再进行base64编码并保存到本地
     * 同时返回原始图片的哈希码
     * @param imageUrl 图片完整URL
     * @param targetPath 保存路径
     * @param key 加密密钥（16字节）
     * @return 包含加密后文件路径和原始图片哈希码的对象
     * @throws Exception
     */
    public static DownloadResult downloadEncryptImage(String imageUrl, Path targetPath, String key) throws Exception {
        // 安全校验
        validateImageUrl(imageUrl);

        HttpGet httpGet = new HttpGet(imageUrl);
        try (CloseableHttpResponse response = httpClient.execute(httpGet);
             InputStream inputStream = response.getEntity().getContent()) {

            // 读取图片内容到字节数组
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            byte[] data = new byte[16384];
            int nRead;
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
            byte[] imageBytes = buffer.toByteArray();
            // 生成原始图片的哈希码
            String imageHash = generateHash(imageBytes);

            // 第一次Base64编码
            String base64Image = Base64.getEncoder().encodeToString(imageBytes);

            // AES PCK7加密
            String encryptedBytes = AESDecryptor.encryptAESImage(base64Image.getBytes(StandardCharsets.UTF_8), key, "0000000000000000");


            // 创建父目录
            Files.createDirectories(targetPath.getParent());

            // 构建最终文件路径
            Path finalPath = Paths.get(targetPath.toString() + ".base64.encrypt");

            // 将最终Base64编码内容写入文件（
            try (BufferedWriter writer = Files.newBufferedWriter(finalPath, StandardCharsets.UTF_8)) {
                writer.write(encryptedBytes);
            }
            return new DownloadResult(finalPath.toString(), imageHash);
        }
    }
    /**
     * 生成字节数组的SHA-256哈希码
     * hashCode 生成40个字节的字符串
     * @param data 待生成哈希码的字节数组
     * @return 哈希码的十六进制字符串
     * @throws
     */
    private static String generateHash(byte[] data) {
        // 使用Guava的Hashing类计算SHA-1哈希值
        com.google.common.hash.HashCode hash = Hashing.sha1().hashBytes(data);
        return hash.toString();
    }


    // 新增 DownloadResult 类，用于封装返回结果
    public static class DownloadResult {
        private  String encryptedFilePath;
        private  String imageHash;
        public DownloadResult(String encryptedFilePath, String imageHash) {
            this.encryptedFilePath = encryptedFilePath;
            this.imageHash = imageHash;
        }

        public String getEncryptedFilePath() {
            return encryptedFilePath;
        }

        public String getImageHash() {
            return imageHash;
        }

        public void setEncryptedFilePath(String encryptedFilePath) {
            this.encryptedFilePath = encryptedFilePath;
        }

        public void setImageHash(String imageHash) {
            this.imageHash = imageHash;
        }
    }
    /**
     * 下载远程图片到本地
     * @param imageUrl 图片完整URL
     * @param targetPath 保存路径
     */
    public static void downloadImage(String imageUrl, Path targetPath) throws IOException {
        // 安全校验
        validateImageUrl(imageUrl);

        HttpGet httpGet = new HttpGet(imageUrl);
        try (CloseableHttpResponse response = httpClient.execute(httpGet);
             InputStream inputStream = response.getEntity().getContent()) {
            
            // 创建父目录
            Files.createDirectories(targetPath.getParent());
            
            // 使用缓冲流提高性能
            try (BufferedOutputStream outputStream =
                    new BufferedOutputStream(Files.newOutputStream(targetPath))) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
        }
    }



    /**
     * 下载图片并使用AES-ECB模式加密
     * @param imageUrl 图片URL
     * @param targetPath 目标路径（加密后的文件）
     * @param key 加密密钥（自动补全到16字节）
     */
    public static void downloadAndEncrypt(String imageUrl, String targetPath, String key) {
        try {
            // 确保目标目录存在
            File targetFile = new File(targetPath);
            File parentDir = targetFile.getParentFile();
            String absolutePath = targetFile.getAbsolutePath();
            StaticLog.info("目标文件路径: {}", absolutePath);
            if (parentDir != null && !parentDir.exists()) {
                boolean created = parentDir.mkdirs();
                if (created) {
                    StaticLog.info("创建目录成功: {}", parentDir.getAbsolutePath());
                } else {
                    StaticLog.error("创建目录失败: {}", parentDir.getAbsolutePath());
                    throw new IOException("无法创建目录: " + parentDir.getAbsolutePath());
                }
            }

            // 下载图片到临时文件
            String tempFilePath = targetPath + ".temp";
            File tempFile = new File(tempFilePath);
            String absoluteTempPath = tempFile.getAbsolutePath();
            StaticLog.info("临时文件路径: {}", absoluteTempPath);
            downloadImageSync(imageUrl, tempFilePath);
            // 等待文件完全写入磁盘
            boolean fileExists = waitForFileExistence(tempFile, 5, TimeUnit.SECONDS);
            if (!fileExists) {
                StaticLog.error("图片下载失败，临时文件不存在或大小为0: {}", tempFilePath);
                debugCheck(tempFile, imageUrl);
                throw new FileNotFoundException("图片下载失败，临时文件不存在或大小为0: " + tempFilePath);
            }
            StaticLog.info("图片下载成功: {}", tempFilePath);
            // 验证文件是否下载成功
            if (!tempFile.exists()) {
                StaticLog.error("图片下载失败，临时文件不存在: {}", tempFilePath);
                throw new FileNotFoundException("图片下载失败，临时文件不存在: " + tempFilePath);
            }
            if (tempFile.length() == 0) {
                StaticLog.error("图片下载失败，临时文件为空: {}", tempFilePath);
                throw new IOException("图片下载失败，临时文件为空: " + tempFilePath);
            }
            StaticLog.info("图片下载成功: {} (大小: {} 字节)", tempFilePath, tempFile.length());

            // 加密临时文件
      //      AESEncryptionDecryptionUtil.encryptImageFileECB(tempFilePath, targetPath, key);
            StaticLog.info("图片加密成功: {}", targetPath);

            // 删除临时文件
            boolean deleted = FileUtil.del(tempFilePath);
            if (deleted) {
                StaticLog.info("临时文件已删除: {}", tempFilePath);
            } else {
                StaticLog.warn("临时文件删除失败: {}", tempFilePath);
            }

        } catch (Exception e) {
            StaticLog.error("下载并加密图片失败: {}", e.getMessage(), e);
            throw new RuntimeException("下载并加密图片失败", e);
        }
    }
    /**
     * 使用同步方式下载图片
     */
    private static void downloadImageSync(String imageUrl, String tempFilePath) {
        File tempFile = new File(tempFilePath);
        // 方法1：使用更底层的Hutool API，确保同步下载
        try (HttpResponse response = HttpRequest.get(imageUrl)
                .timeout(DOWNLOAD_TIMEOUT)
                .execute()) {

            if (!response.isOk()) {
                StaticLog.error("HTTP请求失败，状态码: {}", response.getStatus());
                throw new IOException("HTTP请求失败，状态码: " + response.getStatus());
            }
            StaticLog.info("HTTP请求成功，状态码: {}", response.getStatus());
            // 检查响应内容类型
            StaticLog.info("响应内容类型: {}", response.header("Content-Type"));

            // 检查响应内容长度
            StaticLog.info("响应内容长度: {}", response.header("Content-Length"));
            // 检查响应内容是否为空
            if (response.bodyBytes() == null || response.bodyBytes().length == 0) {
                StaticLog.error("服务器返回空内容");
                throw new IOException("服务器返回空内容");
            }

            // 获取响应内容并写入文件
            byte[] bodyBytes = response.bodyBytes();
            if (bodyBytes == null || bodyBytes.length == 0) {
                StaticLog.error("服务器返回空内容");
                throw new IOException("服务器返回空内容");
            }

            // 写入文件
            try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                fos.write(bodyBytes);
                fos.flush(); // 确保数据写入磁盘
            }
            if (!tempFile.exists()) {
                StaticLog.error("文件写入失败，文件不存在: {}", tempFilePath);
                throw new IOException("文件写入失败，文件不存在: " + tempFilePath);
            }

            if (tempFile.length() == 0) {
                StaticLog.error("文件写入失败，文件为空: {}", tempFilePath);
                throw new IOException("文件写入失败，文件为空: " + tempFilePath);
            }

            StaticLog.info("已将响应内容写入文件: {} (大小: {} 字节)",
                    tempFilePath, tempFile.length());
        } catch (Exception e) {
            StaticLog.error("下载图片时发生异常: {}", e.getMessage(), e);
            throw new RuntimeException("下载图片时发生异常", e);
        }


    }
    /**
     * 调试检查，提供更多信息帮助定位问题
     */
    private static void debugCheck(File file, String imageUrl) {
        try {
            // 检查目标目录权限
            File parentDir = file.getParentFile();
            StaticLog.info("检查目录权限: {}", parentDir.getAbsolutePath());
            StaticLog.info("目录是否存在: {}", parentDir.exists());
            StaticLog.info("目录是否可读: {}", parentDir.canRead());
            StaticLog.info("目录是否可写: {}", parentDir.canWrite());

            // 检查磁盘空间
            long freeSpace = parentDir.getFreeSpace();
            long totalSpace = parentDir.getTotalSpace();
            StaticLog.info("磁盘可用空间: {} MB / {} MB",
                    freeSpace / (1024 * 1024),
                    totalSpace / (1024 * 1024));

            // 尝试连接URL（不下载内容）
            try {
                HttpResponse response = HttpRequest.get(imageUrl)
                        .timeout(10000)
                        .execute();

                StaticLog.info("URL连接测试 - 状态码: {}", response.getStatus());
                StaticLog.info("URL连接测试 - 内容长度: {}", response.header("Content-Length"));
                StaticLog.info("URL连接测试 - 内容类型: {}", response.header("Content-Type"));

            } catch (Exception e) {
                StaticLog.error("URL连接测试失败: {}", e.getMessage());
            }

        } catch (Exception e) {
            StaticLog.error("调试检查时发生异常: {}", e.getMessage(), e);
        }
    }
    /**
     * 等待文件存在并确保其大小大于0
     */
    private static boolean waitForFileExistence(File file, int timeout, TimeUnit unit) {
        long timeoutMillis = unit.toMillis(timeout);
        long startTime = System.currentTimeMillis();
        int checkCount = 0;

        while (System.currentTimeMillis() - startTime < timeoutMillis) {
            checkCount++;
            boolean exists = file.exists();
            long size = exists ? file.length() : 0;

            // 每5次检查输出一次日志
            if (checkCount % 5 == 0) {
                StaticLog.info("等待文件写入完成: {} (存在: {}, 大小: {} 字节)",
                        file.getAbsolutePath(), exists, size);
            }

            if (exists && size > 0) {
                StaticLog.info("文件已就绪: {} (大小: {} 字节, 检查次数: {})",
                        file.getAbsolutePath(), size, checkCount);
                return true;
            }

            // 短暂休眠，避免CPU占用过高
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return false;
            }
        }

        // 超时后输出最终状态
        boolean exists = file.exists();
        long size = exists ? file.length() : 0;
        StaticLog.info("等待文件超时: {} (存在: {}, 大小: {} 字节, 检查次数: {})",
                file.getAbsolutePath(), exists, size, checkCount);

        return exists && size > 0;
    }
    /**
     * URL安全校验
     */
    private static void validateImageUrl(String url) {
        try {
            URI uri = new URI(url);
            
            // 只允许HTTP/HTTPS协议
            if (!"http".equalsIgnoreCase(uri.getScheme()) && 
                !"https".equalsIgnoreCase(uri.getScheme())) {
                throw new SecurityException("非法的协议类型: " + uri.getScheme());
            }
            

        } catch (URISyntaxException e) {
            throw new IllegalArgumentException("无效的URL格式");
        }
    }


}